/**
 * WebSocket 工具类
 * 用于管理WebSocket连接和通信
 */

class WebSocketClient {
  constructor() {
    this.socket = null;
    this.socketStatus = 'closed'; // 连接状态：closed, connecting, connected
    this.reconnectAttempts = 0; // 重连尝试次数
    this.maxReconnectAttempts = 5; // 最大重连次数
    this.reconnecting = false; // 是否正在重连
    this.heartbeatTimer = null; // 心跳检测定时器
    this.lastMessageTime = null; // 最后接收消息的时间
    this.messageCallbacks = []; // 消息回调函数列表
    this.statusCallbacks = []; // 状态回调函数列表
    
    // 从环境变量中获取连接模式，默认为直连模式
    this.directConnect = process.env.VUE_APP_WS_DIRECT_CONNECT !== 'false';
  }

  /**
   * 连接WebSocket
   * @param {String} token 用户token
   * @param {String} path WebSocket路径，例如：'/ws/ma/chat/'
   */
  connect(token, path) {
    if (!token) {
      console.error('WebSocket连接失败：缺少Token');
      return;
    }

    // 如果已经连接或正在连接中，则不再重复连接
    if (this.socket && 
        (this.socket.readyState === WebSocket.OPEN || 
         this.socket.readyState === WebSocket.CONNECTING)) {
      console.log('WebSocket已连接或正在连接中，无需重复连接');
      return;
    }

    // 如果正在重连中，避免重复连接
    if (this.reconnecting) {
      console.log('已有重连过程正在进行中，跳过此次连接请求');
      return;
    }

    try {
      // 先关闭之前的连接
      this.close();
      
      // 设置重连状态
      this.reconnecting = true;

      // 从环境变量获取WebSocket路径，如果传入path则优先使用传入的path
      const wsPath = path || process.env.VUE_APP_WS_PATH || '/ws/ma/chat/';
      
      // 获取WebSocket URL - 根据之前的连接情况选择合适的连接方式
      let wsUrl = '';
      if (this.directConnect) {
        // 如果需要直连后端
        const backendPort = process.env.VUE_APP_WS_BACKEND_PORT || '8080'; // 后端服务端口，从环境变量获取或默认8080
        const hostname = window.location.hostname;
        wsUrl = window.location.protocol === 'https:' 
          ? `wss://${hostname}:${backendPort}${wsPath}${token}`
          : `ws://${hostname}:${backendPort}${wsPath}${token}`; 
        console.log('使用直连方式:', wsUrl);
      } else {
        // 通过Nginx代理连接
        if (window.location.protocol === 'https:') {
          // HTTPS环境
          wsUrl = `wss://${window.location.host}${wsPath}${token}`;
        } else {
          // HTTP环境
          wsUrl = `ws://${window.location.host}${wsPath}${token}`;
        }
        console.log('使用代理方式:', wsUrl);
      }
      
      console.log('准备连接WebSocket，URL:', wsUrl, '协议:', window.location.protocol);

      // 创建WebSocket连接
      this.socket = new WebSocket(wsUrl);
      this.socketStatus = 'connecting'; // 添加连接中状态
      this._notifyStatusChange();

      // 连接成功回调
      this.socket.onopen = () => {
        this.socketStatus = 'connected';
        console.log('WebSocket连接成功');
        
        // 重置重连计数
        this.reconnectAttempts = 0;
        this.reconnecting = false;
        
        // 通知状态变化
        this._notifyStatusChange();
        
        // 发送一个心跳消息以确认连接
        this.startHeartbeat();
      };

      // 连接关闭回调
      this.socket.onclose = (event) => {
        // 如果已经是关闭状态，则不重复处理
        if (this.socketStatus === 'closed') {
          return;
        }
        
        this.socketStatus = 'closed';
        console.log('WebSocket连接关闭，代码:', event.code, '原因:', event.reason);
        
        // 通知状态变化
        this._notifyStatusChange();
        
        // 连接关闭后，允许重新尝试连接
        this.reconnecting = false;
        
        // 正常关闭（代码1000）或用户请求关闭时不自动重连
        if (event.code === 1000 || event.wasClean) {
          console.log('WebSocket正常关闭，不进行重连');
          return;
        }
        
        // 尝试重连，但不改变连接模式
        this.reconnect(token, path);
      };

      // 连接错误回调
      this.socket.onerror = (error) => {
        // 尝试提取更多错误信息
        let errorDetails = '未知错误';
        try {
          errorDetails = JSON.stringify(error);
        } catch (e) {
          errorDetails = '错误对象无法序列化: ' + e.message;
        }
        
        console.error('WebSocket错误详情:', errorDetails);
        console.error('WebSocket连接失败，URL:', wsUrl);
        
        // 通知状态变化
        this._notifyStatusChange();
        
        // 连接出错后，允许重新尝试其他连接方式
        this.reconnecting = false;
      };

      // 接收消息回调
      this.socket.onmessage = (event) => {
        // 更新最后接收消息的时间
        this.lastMessageTime = new Date().getTime();
        console.log('收到WebSocket消息:', event.data);
        
        // 触发消息回调
        this._notifyMessageReceived(event.data);
      };

    } catch (err) {
      this.reconnecting = false;
      console.error('创建WebSocket实例时出错:', err.message);
    }
  }

  /**
   * 重新连接WebSocket
   * @param {String} token 用户token
   * @param {String} path WebSocket路径
   */
  reconnect(token, path) {
    // 如果已经连接或正在连接中，则不再重连
    if (this.socket && 
        (this.socket.readyState === WebSocket.OPEN || 
         this.socket.readyState === WebSocket.CONNECTING)) {
      console.log('WebSocket已连接或正在连接中，无需重连');
      return;
    }
    
    if (this.socketStatus === 'closed' && !this.reconnecting && this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      console.log(`准备在3秒后重连WebSocket... (尝试 ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
      
      setTimeout(() => {
        console.log('开始重连WebSocket');
        this.connect(token, path);
      }, 3000); // 3秒后重连
    } else if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.log('已达到最大重连次数，请手动刷新页面重试');
    } else if (this.reconnecting) {
      console.log('已有重连进程正在执行，跳过此次重连');
    } else {
      console.log('当前状态不需要重连:', this.socketStatus);
    }
  }

  /**
   * 开始WebSocket心跳检测
   */
  startHeartbeat() {
    // 清除之前的心跳检测
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
    }
    
    // 记录首次连接成功的时间
    if (!this.lastMessageTime) {
      this.lastMessageTime = new Date().getTime();
    }
    
    // 每30秒发送一次心跳
    this.heartbeatTimer = setInterval(() => {
      if (this.socket && this.socket.readyState === WebSocket.OPEN) {
        // 发送心跳消息，确保连接活跃
        try {
          this.socket.send('PING');
          console.log('发送WebSocket心跳...');
        } catch (e) {
          console.error('发送心跳消息失败:', e);
        }
        
        // 检查上次接收消息的时间，如果太久没收到消息则重连
        const now = new Date().getTime();
        if (this.lastMessageTime && (now - this.lastMessageTime > 120000)) { // 2分钟超时
          console.log('长时间未收到消息，重新连接WebSocket');
          // 重置重连状态，允许重连
          this.reconnecting = false;
          
          // 获取当前URL中的token
          const currentUrl = this.socket.url;
          const token = currentUrl.substring(currentUrl.lastIndexOf('/') + 1);
          const path = currentUrl.substring(0, currentUrl.lastIndexOf('/') + 1);
          
          this.reconnect(token, path);
        }
      }
    }, 30000);
  }

  /**
   * 关闭WebSocket连接
   */
  close() {
    // 清除心跳定时器
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
    
    // 重置状态，确保不会触发重连
    this.reconnecting = false;
    this.reconnectAttempts = 0;
    
    if (this.socket) {
      try {
        // 保存当前状态以防止重复通知
        const wasConnected = this.socketStatus === 'connected';
        
        if (this.socket.readyState === WebSocket.OPEN) {
          // 正常关闭，使用代码1000（正常关闭）
          this.socket.close(1000, '用户主动关闭');
          console.log('已关闭WebSocket连接');
        } else if (this.socket.readyState === WebSocket.CONNECTING) {
          // 连接中的状态也需要关闭
          this.socket.close(1000, '连接中断');
          console.log('中断WebSocket连接');
        }
        
        // 移除所有事件监听器以防止内存泄漏
        this.socket.onopen = null;
        this.socket.onclose = null;
        this.socket.onerror = null;
        this.socket.onmessage = null;
        
        // 手动设置状态，避免触发onclose中的重连
        if (wasConnected) {
          this.socketStatus = 'closed';
          this._notifyStatusChange();
        }
      } catch (e) {
        console.error('关闭WebSocket出错:', e);
      }
      this.socket = null;
    } else {
      this.socketStatus = 'closed';
      this._notifyStatusChange();
    }
  }

  /**
   * 发送消息
   * @param {String} message 要发送的消息
   */
  send(message) {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
      return true;
    } else {
      console.error('WebSocket未连接，无法发送消息');
      return false;
    }
  }

  /**
   * 添加消息接收回调
   * @param {Function} callback 回调函数，接收消息作为参数
   */
  onMessage(callback) {
    if (typeof callback === 'function') {
      this.messageCallbacks.push(callback);
    }
  }

  /**
   * 添加状态变化回调
   * @param {Function} callback 回调函数，接收状态作为参数
   */
  onStatusChange(callback) {
    if (typeof callback === 'function') {
      this.statusCallbacks.push(callback);
    }
  }

  /**
   * 移除消息接收回调
   * @param {Function} callback 要移除的回调函数
   */
  removeMessageCallback(callback) {
    const index = this.messageCallbacks.indexOf(callback);
    if (index !== -1) {
      this.messageCallbacks.splice(index, 1);
    }
  }

  /**
   * 移除状态变化回调
   * @param {Function} callback 要移除的回调函数
   */
  removeStatusCallback(callback) {
    const index = this.statusCallbacks.indexOf(callback);
    if (index !== -1) {
      this.statusCallbacks.splice(index, 1);
    }
  }

  /**
   * 通知所有消息回调
   * @param {String} message 收到的消息
   */
  _notifyMessageReceived(message) {
    this.messageCallbacks.forEach(callback => {
      try {
        callback(message);
      } catch (error) {
        console.error('执行消息回调出错:', error);
      }
    });
  }

  /**
   * 通知所有状态回调
   */
  _notifyStatusChange() {
    this.statusCallbacks.forEach(callback => {
      try {
        callback(this.socketStatus);
      } catch (error) {
        console.error('执行状态回调出错:', error);
      }
    });
  }

  /**
   * 获取当前连接状态
   * @returns {String} 连接状态
   */
  getStatus() {
    return this.socketStatus;
  }
}

// 导出单例
export default new WebSocketClient(); 